package cn.xt.forum.provider;

import cn.xt.forum.cache.TemporaryCache;
import cn.xt.forum.cache.TinifyPngCache;
import cn.xt.forum.dto.UserDTO;
import cn.xt.forum.exception.CustomizeErrorCode;
import cn.xt.forum.exception.CustomizeException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.StorageClass;
import com.qcloud.cos.region.Region;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.nlp.v20190408.NlpClient;
import com.tencentcloudapi.nlp.v20190408.models.KeywordsExtractionRequest;
import com.tencentcloudapi.nlp.v20190408.models.KeywordsExtractionResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import sun.misc.BASE64Encoder;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class QCloudProvider {

    @Value("${qcloud.secret-id}")
    private String secretId;

    @Value("${qcloud.secret-key}")
    private String secretKey;

    // bucket名需包含appid
    @Value("${qcloud.cos.bucket-name}")
    private String bucketName;

    @Value("${qcloud.cos.region}")
    private String region;

    @Value("${qcloud.cos.objecturl}")
    private String objecturl;

    @Value("${qcloud.ci.objecturl}")
    private String ciObjecturl;

    @Value("${site.main.domain}")
    private String domain;

    @Value("${qcloud.ci.enable}")
    private int ciEnable;

    @Value("${tinify.enable}")
    private int tinifyEnable;

    @Value("${tinify.minContentLength}")
    private Long tinifyMinContentLength;

    @Autowired
    private TinifyPngCache tinifyPngCache;

    @Autowired
    private TemporaryCache temporaryCache;

    public String upload(InputStream fileStream, String contentType, UserDTO user, Long contentLength) {

        String fileName = getFileName(contentType);
        String imgUrl = uploadtoBucket(fileStream, "img", contentType, user, fileName, contentLength);
        if ("image/png".equals(contentType) && tinifyEnable == 1 && contentLength > tinifyMinContentLength) {
            System.out.println("add:" + imgUrl);
            tinifyPngCache.add(imgUrl, user, fileName);
        }
        if (ciEnable == 1) {
            imgUrl = imgUrl.replace(objecturl, ciObjecturl);
        }
        return imgUrl;
    }


    public String upload(InputStream fileStream, String contentType, UserDTO user, String fileName,
                         Long contentLength) {

        String initUrl = uploadtoBucket(fileStream, "img", contentType, user, fileName, contentLength);
        String imgUrl = initUrl;
        if ("image/png".equals(contentType) && tinifyEnable == 1 && contentLength > tinifyMinContentLength) {
            System.out.println("add:" + imgUrl);
            tinifyPngCache.add(imgUrl, user, fileName);
        }
        if (ciEnable == 1) {
            ImageInfo imageInfo = getImageInfo(imgUrl);
            if (Integer.parseInt(imageInfo.getWidth()) > 400 && Integer.parseInt(imageInfo.getHeight()) > 150) {
                String watermark = "@" + user.getName() + " " + domain;
                try {
                    byte[] data = watermark.getBytes("utf-8");
                    String encodeBase64 = new BASE64Encoder().encode(data);
                    watermark = encodeBase64.replace('+', '-');
                    watermark = watermark.replace('/', '_');
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                imgUrl = initUrl + "?imageView2/q/75|watermark/2/text/" + watermark + "/fill/IzNEM0QzRA/fontsize/18" +
                        "/dissolve/80/gravity/SouthEast/dx/20/dy/10/";

            }
            imgUrl = imgUrl.replace(objecturl, ciObjecturl);
        }


        return imgUrl;
    }

    public String uploadAvatar(InputStream inputStream, String contentType, UserDTO user, String fileName,
                               Long contentLength) {
        String initUrl = uploadtoBucket(inputStream, "avatar", contentType, user, fileName, contentLength);
        String avatarUrl = initUrl;
        if (ciEnable == 1) {
            initUrl = initUrl + "?imageMogr2/scrop/168x168/crop/168x168/gravity/center";
            avatarUrl = uploadUrltoBucket(initUrl, "avatar", contentType, user, fileName);
        }
        return avatarUrl;
    }

    private String uploadUrltoBucket(String initUrl, String fileType, String contentType, UserDTO user,
                                     String fileName) {
        URL url = null;
        String finalUrl = null;
        InputStream fileStream = null;
        try {
            url = new URL(initUrl);
            URLConnection con = url.openConnection();
            con.setConnectTimeout(5 * 1000);
            fileStream = con.getInputStream();
            finalUrl = uploadtoBucket(fileStream, fileType, contentType, user, fileName,
                    Long.valueOf(con.getContentLength()));
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {//解决流资源未释放的问题
            if (fileStream != null) {
                try {
                    fileStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return finalUrl;
    }

    public String uploadtoBucket(InputStream inputStream, String fileType, String contentType, UserDTO user,
                                 String fileName, Long contentLength) {

        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
        ClientConfig clientConfig = new ClientConfig(new Region(region));
        COSClient cosclient = new COSClient(cred, clientConfig);

        String key = "upload/user/" + user.getId() + "/" + fileType + "/" + fileName;

        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(contentLength);
        objectMetadata.setContentType("contentType");

        PutObjectRequest putObjectRequest =
                new PutObjectRequest(bucketName, key, inputStream, objectMetadata);
        putObjectRequest.setStorageClass(StorageClass.Standard);
        try {
            PutObjectResult putObjectResult = cosclient.putObject(putObjectRequest);
        } catch (CosClientException e) {
            log.error("upload error,{}", key, e);
            throw new CustomizeException(CustomizeErrorCode.FILE_UPLOAD_FAIL);
        }
        cosclient.shutdown();
        return objecturl + key;
    }

    private ImageInfo getImageInfo(String url) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url + "?imageInfo")
                .build();
        ImageInfo imageInfo = null;
        try {
            Response response = client.newCall(request).execute();
            String string = response.body().string();
            System.out.println(string);
            imageInfo = JSON.parseObject(string, ImageInfo.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return imageInfo;
    }


    public String getKeywords(String text, int num, double score) {
        String keyWordString = "";
        try {

            Credential cred = new Credential(secretId, secretKey);

            HttpProfile httpProfile = new HttpProfile();
            httpProfile.setEndpoint("nlp.tencentcloudapi.com");

            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);

            NlpClient client = new NlpClient(cred, "ap-guangzhou", clientProfile);

            String params = "{\"Num\":" + num + ",\"Text\":\"" + text + "\"}";
            KeywordsExtractionRequest req = KeywordsExtractionRequest.fromJsonString(params,
                    KeywordsExtractionRequest.class);

            KeywordsExtractionResponse resp = client.KeywordsExtraction(req);
            JSONObject obj = JSON.parseObject(KeywordsExtractionRequest.toJsonString(resp));
            JSONArray keywords = obj.getJSONArray("Keywords");
            List<Keywords> keywordsList = JSONObject.parseArray(keywords.toJSONString(), Keywords.class);

            if (keywordsList.size() > 0)
                for (Keywords keyword : keywordsList) {
                    if (keyword.getScore() > score) keyWordString = keyWordString + "," + keyword.getWord();
                }
        } catch (TencentCloudSDKException e) {
            System.out.println(e.toString());
        }
        return keyWordString;
    }

    public String getFileName(String contentType) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String timeStr = sdf.format(new Date());
        String[] ss = contentType.split("/");
        String str = RandomStringUtils.random(2,
                "abcdefghijklmnopqrstuvwxyz1234567890");
        String name = timeStr + "_" + str + "." + ss[1];
        return name;
    }

    @Data
    static class Keywords {
        Double Score;
        String Word;
    }

    @Data
    static class ImageInfo {
        String format;
        String width;
        String height;
        String size;
        String md5;
        String photo_rgb;
    }

}
